package dtm

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"kpt-dtm/model"
	"kpt-dtm/model/dtm"
	"kpt-dtm/model/yyn"
	"kpt-dtm/pkg"
	"kpt-dtm/service/http"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"time"

	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
	"gitee.com/xuyiping_admin/pkg/xerr"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

var (
	SessionId = ""
	ApiUrl    = ""
)

func (s *StoreEntry) OldAuth(ctx context.Context, id int64) (interface{}, error) {
	appPasture := &model.AppPasture{}
	if err := s.DB.Model(new(model.AppPasture)).
		Where("id = ?", id).
		Where("is_show = ?", model.IsShowOK).
		First(appPasture).Error; err != nil {
		return nil, xerr.WithStack(err)
	}

	if err := s.Authentication(appPasture); err != nil {
		return nil, xerr.WithStack(err)
	}
	return &model.SessionModel{
		SessionId: SessionId,
		ApiUrl:    ApiUrl,
	}, nil
}

func (s *StoreEntry) OldTest(ctx context.Context, id int64, name string) error {
	appPasture := &model.AppPasture{}
	if err := s.DB.Model(new(model.AppPasture)).
		Where("id = ?", id).
		Where("is_show = ?", model.IsShowOK).
		First(appPasture).Error; err != nil {
		return xerr.WithStack(err)
	}

	yConfig, err := s.GetYConfig(appPasture.Id)
	if err != nil {
		zaplog.Error("OldAppPastureExecute", zap.Any("GetYConfig", err), zap.Any("app", appPasture))
		return xerr.WithStack(err)
	}

	yMqtt, err := s.GetYMqtt(appPasture.Id)
	if err != nil {
		zaplog.Error("OldAppPastureExecute", zap.Any("GetYMqtt", err), zap.Any("app", appPasture))
	}

	funcList := s.OldExecuteFunctions()
	for _, f := range funcList {
		funcName := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() // 获取函数名，注意这种方法并不推荐，因为它使用了反射和运行时包，可能不是最可靠或最高效的方法
		funcName = funcName[strings.LastIndex(funcName, ".")+1:]           // 提取函数名部分
		funcName = funcName[:strings.LastIndex(funcName, "-")]             // 提取函数名部分

		if name != "" && funcName != name {
			continue
		}
		zaplog.Info("OldAppPastureExecute", zap.String("正在执行的函数", funcName))
		if err = f(appPasture, yConfig, yMqtt); err != nil {
			return xerr.WithStack(err)
		}
	}
	return nil
}

func (s *StoreEntry) OldAppPastureExecute(app *model.AppPasture) error {
	//ctx := context.Background()
	yConfig, err := s.GetYConfig(app.Id)
	if err != nil {
		zaplog.Error("OldAppPastureExecute", zap.Any("GetYConfig", err), zap.Any("app", app))
		return xerr.WithStack(err)
	}

	yMqtt, err := s.GetYMqtt(app.Id)
	if err != nil {
		zaplog.Error("OldAppPastureExecute", zap.Any("GetYMqtt", err), zap.Any("app", app))
		return xerr.WithStack(err)
	}

	// 云养牛更新栏舍信息
	/*if err = s.GetYYNPenList(ctx, app, yConfig); err != nil {
		zaplog.Error("OldAppPastureExecute", zap.Any("GetYYNPenList", err), zap.Any("app", app))
	}*/

	funcList := s.OldExecuteFunctions()
	nowTime := time.Now().Format(pkg.LayoutYear)
	zaplog.Info("OldAppPastureExecute",
		zap.Any("FunctionStatuses", FunctionStatuses),
		zap.Any("app", app),
		zap.Any("nowTime", nowTime),
		zap.Any("funcList", funcList),
	)
	for _, f := range funcList {
		funcName := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() // 获取函数名，注意这种方法并不推荐，因为它使用了反射和运行时包，可能不是最可靠或最高效的方法
		funcName = funcName[strings.LastIndex(funcName, ".")+1:]           // 提取函数名部分
		funcName = funcName[:strings.LastIndex(funcName, "-")]             // 提取函数名部分
		if FunctionStatuses[funcName] == nowTime {
			zaplog.Info("OldAppPastureExecute",
				zap.Any("app", app),
				zap.String("跳过已执行的函数", funcName),
				zap.String("nowTime", nowTime),
				zap.Any("FunctionStatuses", FunctionStatuses),
			)
			continue
		}

		zaplog.Info("OldAppPastureExecute",
			zap.String("正在执行的函数", funcName),
			zap.Any("app", app),
			zap.Any("yConfig", yConfig),
			zap.Any("yMqtt", yMqtt),
		)
		if err = f(app, yConfig, yMqtt); err != nil {
			zaplog.Error("OldAppPastureExecute", zap.Any("app", app), zap.String("functionName", funcName), zap.Any("err", err))
			s.CreateErrorLog(app.Id, funcName, err.Error())
			continue
		}
		// 这两步暂时不考虑一致性
		FunctionStatuses[funcName] = nowTime
		zaplog.Info("OldAppPastureExecute", zap.String("执行结束的函数", funcName))
		if err = s.CreateLoop(app.Id, funcName); err != nil {
			zaplog.Error("OldAppPastureExecute", zap.Any("app", app), zap.Any("CreateLoop", err))
		}
	}
	return nil
}

func (s *StoreEntry) OldExecuteFunctions() []func(*model.AppPasture, *model.YConfig, *model.YMqtt) error {
	functions := []func(*model.AppPasture, *model.YConfig, *model.YMqtt) error{
		s.RecipeList,
		s.SpreadingList,
	}
	return functions
}

func (s *StoreEntry) Authentication(app *model.AppPasture) error {
	url := app.LoginUrl
	body := dtm.AuthRequest{
		Type:         dtm.ApiType,
		CompanyCode:  app.CompanyCode,
		ResellerCode: app.ResellerCode,
		Pwd:          app.LoginPassword,
	}
	header := s.GetHeader(nil)
	res, err := s.HttpClient.DoPost(url, body, header)
	if err != nil {
		zaplog.Error("Authentication", zap.Any("err", err), zap.Any("body", body), zap.Any("header", header))
		return xerr.WithStack(err)
	}

	authResponse := &dtm.AuthResponse{}
	if err = json.Unmarshal(res, authResponse); err != nil {
		zaplog.Error("Authentication", zap.Any("err", err), zap.Any("body", body), zap.Any("header", header))
		return xerr.WithStack(err)
	}

	if authResponse.ErrorCode != dtm.ErrorCode {
		return xerr.WithStack(err)
	}

	if authResponse.SessionId == "" || authResponse.ApiWebSericeUrl == "" {
		return xerr.New("SessionId OR ApiWebSericeUrl is empty")
	}

	SessionId = authResponse.SessionId
	// 确保 URL 正确拼接，避免缺少斜杠
	if strings.HasSuffix(authResponse.ApiWebSericeUrl, "/") {
		ApiUrl = authResponse.ApiWebSericeUrl + "execute"
	} else {
		ApiUrl = authResponse.ApiWebSericeUrl + "/execute"
	}
	return nil
}

func (s *StoreEntry) GetHeader(newHeaderList []*http.Header) []*http.Header {
	headerList := make([]*http.Header, 0)
	headerList = append(headerList, &http.Header{
		Key:   "Content-Type",
		Value: "application/json",
	})
	if newHeaderList != nil && len(newHeaderList) > 0 {
		headerList = append(headerList, newHeaderList...)
	}
	return headerList
}

// GetYYNPenList 跟新云养牛栏舍列表到牧场
func (s *StoreEntry) GetYYNPenList(ctx context.Context, app *model.AppPasture, yConfig *model.YConfig) error {
	res, err := s.SynCowHouseInfo(ctx, yConfig)
	if err != nil {
		return xerr.WithStack(err)
	}
	if res.Status != 1 || res.Content == nil || len(res.Content.CowHouseList) <= 0 {
		return xerr.WithStack(xerr.New("获取数据失败"))
	}

	zaplog.Info("云养牛栏舍数据", zap.Any("data", res))
	// 获取到云养牛栏舍数据后，将数据导入dtm
	for _, v := range res.Content.CowHouseList {
		ncows, _ := strconv.ParseFloat(v.CowAmount, 64)
		if 0 == ncows || ncows > 1000 {
			continue
		}
		// 判断栏舍是否存在
		cowBarn := &model.CowBarn{}
		if err = s.DB.Model(new(model.CowBarn)).
			Where("pasture_id = ?", app.Id).
			Where("house_uuid = ?", v.HouseUuid).
			First(cowBarn).Error; err != nil {
			if !errors.Is(err, gorm.ErrRecordNotFound) {
				return xerr.WithStack(err)
			}
		}
		// 存在则判断栏舍名称和数量是否一致
		if cowBarn.Id > 0 && cowBarn.HouseName == v.HouseName {
			continue
		}

		var (
			dtmPenRes  *dtm.PenValue
			newPenData *dtm.GetPensList
		)

		newPenValue := &dtm.PenValue{
			Name:      v.HouseName,
			Enabled:   true,
			NCows:     int(ncows),
			AdjPerc:   ncows,
			PenRation: make([]*dtm.PenRation, 0),
		}

		// 判断栏舍是否存在，不存在则创建
		if cowBarn.Id <= 0 {
			err = s.CreatedPen(app, newPenValue)
			if err != nil {
				return xerr.WithStack(err)
			}
			newCowBarn := model.NewCowBarn(app.Id, v.HouseUuid, v.HouseName, v.CowAmount, dtmPenRes.PenId)
			if err = s.DB.Model(new(model.CowBarn)).Create(newCowBarn).Error; err != nil {
				return xerr.WithStack(err)
			}
		}

		// 判断栏舍是否存在，存在则更新
		if cowBarn.Id > 0 && (cowBarn.HouseName != v.HouseName || cowBarn.CowNum != v.CowAmount) {
			// 更新栏舍名称和数量
			newPenValue.PenId = cowBarn.PenId
			newPenData, err = s.GetPen(ctx, newPenValue.PenId, app.Id)
			if err != nil {
				continue
			}

			if len(newPenData.Value) <= 0 {
				continue
			}
			newPenValue.LastModify = newPenData.Value[0].LastModify
			newPenValue.RowVersion = newPenData.Value[0].RowVersion

			if err = s.UpdatePen(ctx, newPenValue, newPenValue.PenId, app.Id); err != nil {
				return xerr.WithStack(err)
			}
			if err = s.DB.Model(new(model.CowBarn)).
				Where("id = ?", cowBarn.Id).
				Updates(map[string]interface{}{
					"house_name": v.HouseName,
					"cow_num":    v.CowAmount,
				}).Error; err != nil {
				return xerr.WithStack(err)
			}
		}
	}

	return nil
}

// CreatedPen 创建栏舍
func (s *StoreEntry) CreatedPen(app *model.AppPasture, body *dtm.PenValue) error {

	if err := s.Authentication(app); err != nil {
		return xerr.WithStack(err)
	}
	newHeaderList := make([]*http.Header, 0)
	newHeaderList = append(newHeaderList, &http.Header{
		Key:   "dtmcompanyid",
		Value: app.CompanyCode,
	}, &http.Header{
		Key:   "dtmsessionid",
		Value: SessionId,
	})

	response := &dtm.CreatePenResponse{}
	result, err := s.HttpClient.DoPost(ApiUrl, body, s.GetHeader(newHeaderList))
	if err != nil {
		zaplog.Error("CreatedPen", zap.Any("err", err), zap.Any("body", body), zap.Any("result", string(result)))
		return xerr.WithStack(err)
	}

	if err = json.Unmarshal(result, response); err != nil {
		zaplog.Error("CreatedPen", zap.Any("err", err), zap.Any("body", body), zap.Any("result", string(result)))
		return xerr.WithStack(err)
	}
	if response.Code != dtm.ErrorCode {
		return xerr.Customf("err: %s", response.Message)
	}
	return nil
}

// RecipeList 配方列表
func (s *StoreEntry) RecipeList(app *model.AppPasture, yConfig *model.YConfig, yMqtt *model.YMqtt) error {
	if err := s.Authentication(app); err != nil {
		return xerr.WithStack(err)
	}
	body := &dtm.RecipeListRequest{
		Type:        dtm.RecipeType,
		CompanyCode: app.CompanyCode,
		SessionId:   SessionId,
		FromDate:    "0001-01-01T00:00:00",
	}

	res, err := s.HttpClient.DoPost(ApiUrl, body, nil)
	if err != nil {
		zaplog.Error("RecipeList",
			zap.Any("err", err),
			zap.Any("body", body),
			zap.String("url", ApiUrl),
		)
		return xerr.WithStack(err)
	}

	response := &dtm.RecipeListResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		zaplog.Error("RecipeList", zap.Any("err", err), zap.Any("body", body))
		return xerr.WithStack(err)
	}
	if response.ErrorCode != dtm.ErrorCode {
		return xerr.New("RecipeList Error")
	}

	yMaterialMap := s.GetMaterialMap(app)

	resultData := make([]*yyn.FormulationData, 0)
	// 限制处理的配方数量，避免内存过度使用
	//maxRecipes := 50
	processedCount := 0

	for _, v := range response.Values.Values {
		/*if processedCount >= maxRecipes {
			zaplog.Error("RecipeList: 达到最大处理数量限制", zap.Int("maxRecipes", maxRecipes))
			break
		}*/

		recipeDetail, err := s.RecipeDetailById(app, v)
		if err != nil {
			zaplog.Error("RecipeDetailById", zap.Any("err", err), zap.Any("recipeId", v))
			continue
		}
		processedCount++
		if recipeDetail.Components == nil || recipeDetail.Components.Values == nil {
			continue
		}

		recipeCost := float64(0)
		recipeDetailList := make([]*yyn.FormulationData, 0)
		for i, c := range recipeDetail.Components.Values {
			// 判断配方数据是否存在
			if s.IsCheckFormulation(app.Id, fmt.Sprintf("%d", v), fmt.Sprintf("%d", c.ComponentId)) {
				continue
			}

			key := fmt.Sprintf("%d%s", c.ComponentId, c.Name)
			ingId := fmt.Sprintf("%d", c.ComponentId)
			ingName := c.Name
			if material, ok := yMaterialMap[key]; ok {
				ingId = material.YynIngredientId
				ingName = material.YynIngredientName
			}
			recipeDetailList = append(recipeDetailList, &yyn.FormulationData{
				RecipeId:   fmt.Sprintf("%d", recipeDetail.RecipeId),
				RecipeName: recipeDetail.Name,
				IngId:      ingId,
				IngName:    ingName,
				DmQty:      fmt.Sprintf("%.2f", c.DMPerc),
				AfQty:      fmt.Sprintf("%.2f", c.WeightCow),
				RecipeCost: "",
				MixNo:      fmt.Sprintf("%d", i+1),
				IsPreMix:   recipeDetail.Premix,
				DmPercTot:  0, // todo 暂无
			})
			recipeCost += c.PriceCow
		}

		if len(recipeDetailList) > 0 {
			for _, d := range recipeDetailList {
				d.RecipeCost = fmt.Sprintf("%.2f", recipeCost)
			}
			resultData = append(resultData, recipeDetailList...)

			// 如果数据量过大，分批处理
			if len(resultData) > 1000 {
				zaplog.Error("RecipeList: 数据量过大，分批处理", zap.Int("currentCount", len(resultData)))
				// 这里可以添加分批处理的逻辑
			}
		}
	}

	zaplog.Info("RecipeList: 配方列表处理完成", zap.Any("resultDataLen", len(resultData)))
	if len(resultData) <= 0 {
		return nil
	}
	// 推送配方数据
	if err = s.FormulationDataPush(app.Id, yConfig, yMqtt, resultData); err != nil {
		return xerr.WithStack(err)
	}

	newFormulationList := model.NewFormulationList(app.Id, resultData)
	if err = s.CreateFormulation(newFormulationList); err != nil {
		return xerr.WithStack(err)
	}
	return nil
}

// RecipeDetailById 配方详情
func (s *StoreEntry) RecipeDetailById(app *model.AppPasture, recipeId int) (*dtm.RecipeDetailValue, error) {
	// 检查SessionId是否有效，如果无效才重新认证
	if SessionId == "" {
		if err := s.Authentication(app); err != nil {
			return nil, xerr.WithStack(err)
		}
	}

	body := &dtm.RecipeDetailRequest{
		Type:        dtm.RecipeDetailType,
		CompanyCode: app.CompanyCode,
		SessionId:   SessionId,
		RecipeId:    recipeId,
	}

	res, err := s.HttpClient.DoPost(ApiUrl, body, s.GetHeader(nil))
	if err != nil {
		zaplog.Error("RecipeDetailById", zap.Any("err", err), zap.Any("body", body))
		return nil, xerr.WithStack(err)
	}

	response := &dtm.RecipeDetailResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		zaplog.Error("RecipeDetailById", zap.Any("err", err), zap.Any("body", body))
		return nil, xerr.WithStack(err)
	}
	if response.ErrorCode != dtm.ErrorCode {
		return nil, xerr.New("RecipeDetailById Error")
	}
	return response.Value, nil
}

// SpreadingList 撒料数据和干物质数据
func (s *StoreEntry) SpreadingList(app *model.AppPasture, yConfig *model.YConfig, yMqtt *model.YMqtt) error {
	if err := s.Authentication(app); err != nil {
		return xerr.WithStack(err)
	}
	nowDate := time.Now()
	yesterday := nowDate.AddDate(0, 0, -1).Format(pkg.LayoutYear)
	formDate := fmt.Sprintf("%sT00:00:00", yesterday)
	toDate := fmt.Sprintf("%sT00:00:00", nowDate.Format(pkg.LayoutYear))
	body := &dtm.SpreadingRequest{
		Type:        dtm.SpreadingType,
		CompanyCode: app.CompanyCode,
		SessionId:   SessionId,
		FromDate:    formDate,
		ToDate:      toDate,
	}

	res, err := s.HttpClient.DoPost(ApiUrl, body, s.GetHeader(nil))
	if err != nil {
		zaplog.Error("SpreadingList", zap.Any("err", err), zap.Any("url", ApiUrl), zap.Any("body", body))
		return xerr.WithStack(err)
	}
	response := &dtm.SpreadingResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		zaplog.Error("SpreadingList", zap.Any("err", err), zap.Any("body", body))
		return xerr.WithStack(err)
	}
	if response.ErrorCode != dtm.ErrorCode {
		return xerr.New("RecipeDetailById Error")
	}

	zaplog.Info("SpreadingList", zap.Any("response", response))

	for tmrNo, unloadId := range response.Values.Values {
		if s.IsCheckSpread(app.Id, unloadId) {
			continue
		}

		if err = s.SpreadDetail(app, yConfig, yMqtt, unloadId, tmrNo); err != nil {
			zaplog.Error("SpreadDetail", zap.Any("err", err))
		}
	}

	return nil
}

func (s *StoreEntry) SpreadDetail(app *model.AppPasture, yConfig *model.YConfig, yMqtt *model.YMqtt, unloadId, tmrNo int) error {
	spreadingByIdRequest := &dtm.SpreadingByIdRequest{
		Type:        dtm.SpreadingByIdType,
		CompanyCode: app.CompanyCode,
		SessionId:   SessionId,
		UnloadId:    unloadId,
	}

	spreadingByIdResponse, err := s.HttpClient.DoPost(ApiUrl, spreadingByIdRequest, s.GetHeader(nil))
	zaplog.Info("SpreadingDetail",
		zap.Any("ApiUrl", ApiUrl),
		zap.Any("spreadingByIdResponse", string(spreadingByIdResponse)),
	)
	if err != nil {
		zaplog.Error("SpreadingById", zap.Any("err", err), zap.Any("body", spreadingByIdRequest))
		return xerr.WithStack(err)
	}

	spreadingById := &dtm.SpreadingByIdResponse{}
	if err = json.Unmarshal(spreadingByIdResponse, spreadingById); err != nil {
		zaplog.Error("SpreadingById", zap.Any("err", err), zap.Any("body", spreadingByIdRequest))
		return xerr.WithStack(err)
	}

	resultData := make([]*yyn.UploadDiliverData, 0)
	dryMatterData := make([]*yyn.DryMatter, 0)
	for _, v := range spreadingById.Value.UnloadedPens.Values {
		foundChar := pkg.ContainsRune(v.Name, DropShiftList)
		dropShift := "3"
		if foundChar != rune(0) {
			switch string(foundChar) {
			case "早":
				dropShift = "1"
			case "中":
				dropShift = "2"
			case "夜":
				dropShift = "3"
			default:
				dropShift = "3"
			}
		}
		resultData = append(resultData, &yyn.UploadDiliverData{
			DropDate:     spreadingById.Value.StartTime[0:10],
			TmrNo:        fmt.Sprintf("%d", spreadingById.Value.BatchId),
			DropShift:    dropShift,
			PenId:        fmt.Sprintf("%d", v.PenId),
			PenName:      v.Name,
			CowCount:     fmt.Sprintf("%d", v.AnimalNumber),
			FeedingNo:    fmt.Sprintf("%d", v.PenUnloadId),
			ExpWeight:    fmt.Sprintf("%.2f", v.TotalTargetWeight),
			ActualWeight: fmt.Sprintf("%.2f", v.TotalUnloadedWeight),
			StartTime:    spreadingById.Value.StartTime,
			EndTime:      spreadingById.Value.EndTime,
			TmrName:      spreadingById.Value.Name,
			ElabLoadId:   int64(spreadingById.Value.LoadId),
		})

		// 干物质数据
		dryMatterData = append(dryMatterData, &yyn.DryMatter{
			QualityDate: spreadingById.Value.StartTime[0:10],
			RecipeId:    fmt.Sprintf("%d", spreadingById.Value.RecipeId),
			RecipeName:  spreadingById.Value.Recipe,
			Drymatter:   fmt.Sprintf("%.2f", v.UnloadedChemicalParameters.Values[0].Value),
			StartTime:   spreadingById.Value.StartTime,
			EndTime:     spreadingById.Value.EndTime,
			ElabLoadId:  int64(spreadingById.Value.LoadId),
		})

		// 搅拌数据
		if err = s.LoadData(app, yConfig, yMqtt, spreadingById.Value.LoadId, tmrNo, spreadingById.Value.Recipe); err != nil {
			zaplog.Error("LoadData", zap.Any("err", err))
		}
	}

	if len(resultData) <= 0 {
		return nil
	}

	// 撒料数据推送
	if err = s.SpreadDataPush(app.Id, yConfig, yMqtt, resultData); err != nil {
		return xerr.WithStack(err)
	}

	newSpreadList := model.NewSpreadList(app.Id, resultData)
	if err = s.CreateSpread(newSpreadList); err != nil {
		return xerr.WithStack(err)
	}

	if len(dryMatterData) <= 0 {
		return nil
	}

	// 干物质数据推送
	if err = s.DryMatterDataPush(app.Id, yConfig, yMqtt, dryMatterData); err != nil {
		return xerr.WithStack(err)
	}

	newDryMatterList := model.NewDryMatterList(app.Id, dryMatterData)
	if err = s.CreatedDryMatter(newDryMatterList); err != nil {
		return xerr.WithStack(err)
	}
	return nil
}

// LoadData 搅拌(加料)数据
func (s *StoreEntry) LoadData(app *model.AppPasture, yConfig *model.YConfig, yMqtt *model.YMqtt, loadId, tmrNo int, recipeName string) error {
	loadRequest := &dtm.LoadDataByIdRequest{
		Type:        dtm.LoadDataType,
		CompanyCode: app.CompanyCode,
		SessionId:   SessionId,
		LoadId:      loadId,
	}

	yMaterialMap := s.GetMaterialMap(app)
	loadDataByIdResponse, err := s.HttpClient.DoPost(ApiUrl, loadRequest, s.GetHeader(nil))
	zaplog.Info("LoadData",
		zap.Any("ApiUrl", ApiUrl),
		zap.Any("loadDataByIdResponse", string(loadDataByIdResponse)),
	)
	if err != nil {
		zaplog.Error("LoadData", zap.Any("err", err), zap.Any("body", loadRequest))
		return xerr.WithStack(err)
	}

	loadData := &dtm.LoadDataByIdResponse{}
	if err = json.Unmarshal(loadDataByIdResponse, loadData); err != nil {
		zaplog.Error("loadData", zap.Any("err", err), zap.Any("body", loadRequest))
		return xerr.WithStack(err)
	}

	resultData := make([]*yyn.MixData, 0)
	for i, v := range loadData.Value.LoadedComponents.Values {
		loadDate := []rune(loadData.Value.StartTime)
		foundChar := pkg.ContainsRune(v.Name, DropShiftList)
		dropShift := "3"
		if foundChar != rune(0) {
			switch string(foundChar) {
			case "早":
				dropShift = "1"
			case "中":
				dropShift = "2"
			case "夜":
				dropShift = "3"
			default:
				dropShift = "3"
			}
		}
		ingType := "12"
		if v.Name == "水" {
			ingType = "13"
		}

		materialKey := fmt.Sprintf("%d%s", v.ComponentId, v.Name)
		ingId, ingName := fmt.Sprintf("%d", v.ComponentId), v.Name
		if yMaterial, ok := yMaterialMap[materialKey]; ok {
			ingId = yMaterial.YynIngredientId
			ingName = yMaterial.YynIngredientName
		}

		resultData = append(resultData, &yyn.MixData{
			LoadDate:       string(loadDate[0:10]),
			TmrNo:          fmt.Sprintf("%d", tmrNo+1),
			LoadShift:      dropShift,
			RecipeId:       fmt.Sprintf("%d", loadData.Value.RecipeId),
			RecipeName:     recipeName,
			IngId:          ingId,
			IngName:        ingName,
			IngType:        ingType,
			DmPct:          "",
			MixNo:          fmt.Sprintf("%d", i+1),
			AllowableError: fmt.Sprintf("%.2f", v.TotalLoadedWeight-v.TotalTargetWeight),
			ExpWeight:      fmt.Sprintf("%.2f", v.TotalTargetWeight),
			ActualWeight:   fmt.Sprintf("%.2f", v.TotalLoadedWeight),
			StartTime:      loadData.Value.StartTime,
			EndTime:        loadData.Value.EndTime,
			TmrName:        loadData.Value.MachineName,
			ElabLoadId:     loadId,
		})
	}

	if len(resultData) <= 0 {
		return nil
	}
	// 搅拌数据推送
	if err = s.MixingDataPush(app.Id, yConfig, yMqtt, resultData); err != nil {
		return xerr.WithStack(err)
	}

	newMixDataList := model.NewMixDataList(app.Id, resultData)
	if err = s.CreateMixing(newMixDataList); err != nil {
		return xerr.WithStack(err)
	}
	return nil
}

func (s *StoreEntry) GetMaterialMap(app *model.AppPasture) map[string]*model.YMaterial {
	yMaterialList := make([]*model.YMaterial, 0)
	if err := s.DB.Model(new(model.YMaterial)).
		Where("pasture_id = ?", app.Id).
		Find(&yMaterialList).Error; err != nil {
		zaplog.Error("YMaterial is Empty", zap.Any("yMaterialList", yMaterialList), zap.Any("app", app))
	}

	yMaterialMap := model.YMaterialSlice(yMaterialList).ToMap()
	if len(yMaterialMap) <= 0 {
		zaplog.Error("yMaterialMap is Empty", zap.Any("yMaterialList", yMaterialList), zap.Any("app", app))
	}
	return yMaterialMap
}
